package com.glink.manage.common;

import com.glink.common.exception.GeneralSimpleException;
import com.glink.common.util.BaseCommonUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.Map.Entry;

public class FileTools {
    public static final String IMG_SUFFIX = ".jpg";
    public final static Map<String, String> FILE_TYPE_MAP = new HashMap<>();
    private final static Logger LOG = LoggerFactory.getLogger(FileTools.class);
    private static final String[] SUPPORT_FILE_SUFFIX = {"jpg", "jpeg", "png"};
    private static final String[] SUPPORT_JPEG_SUFFIX = {"jpg", "jpeg"};
    private static final String[] SUPPORT_OFFICE_SUFFIX = {"xls", "doc"};
    private static final String[] SUPPORT_OFFICE2_SUFFIX = {"xlsx", "docx", "zip", "ofd"};
    private static final String STRING_OFFICE = "office";
    private static final String STRING_OFFICE_2 = "office2";
    public static final String STRING_JPG = "jpg";

    private static void getAllFileType() {
        // JPEG
        FILE_TYPE_MAP.put(STRING_JPG, "FFD8FF");
        // PNG
        FILE_TYPE_MAP.put("png", "89504E47");
        // CAD
        FILE_TYPE_MAP.put("dwg", "41433130");
        FILE_TYPE_MAP.put("rar", "52617221");
        // PhotoShop
        FILE_TYPE_MAP.put("psd", "38425053");
        //xls.or.doc
        FILE_TYPE_MAP.put(STRING_OFFICE, "D0CF11E0");
        FILE_TYPE_MAP.put(STRING_OFFICE_2, "504B0304");
        FILE_TYPE_MAP.put("pdf", "255044462D312E");
        // @XDA   
        FILE_TYPE_MAP.put("cebx", "405844410000");
        // Founder CEB 
        FILE_TYPE_MAP.put("ceb", "466F756E64657220434542");
        
    }


    /**
     * 通过读取文件头部获得文件类型
     *
     * @return 文件类型
     */
    public static String getFileType(InputStream is, String fileType2Check) {
        getAllFileType();
        String fileExtendName = null;
        try {
            byte[] b = new byte[16];
            is.read(b, 0, b.length);
            String filetypeHex = String.valueOf(bytesToHexString(b));
            Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
            while (entryiterator.hasNext()) {
                Entry<String, String> entry = entryiterator.next();
                String fileTypeHexValue = entry.getValue();
                if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                    fileExtendName = entry.getKey();
                    break;
                }
            }
            return fileExtendName;
        } catch (Exception exception) {
            exception.printStackTrace();
        } finally {
            IOUtils.closeQuietly(is);
        }
        return null;
    }

    /**
     * 通过读取文件头部获得文件类型
     *
     * @return 文件类型
     */
    public static String getFileType(byte[] data) {
        getAllFileType();
        String fileExtendName = null;
        try {
            byte[] b = new byte[16];
            b = Arrays.copyOfRange(data, 0, 16);
            String filetypeHex = String.valueOf(bytesToHexString(b));
            Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
            while (entryiterator.hasNext()) {
                Entry<String, String> entry = entryiterator.next();
                String fileTypeHexValue = entry.getValue();
                if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                    fileExtendName = entry.getKey();
                    break;
                }
            }
            return fileExtendName;
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return null;
    }


    /**
     * 获得文件头部字符串
     *
     * @param src
     * @return
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (byte b : src) {
            int v = b & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 生成新的文件名
     *
     * @return
     */
    public static String getNewFileName(String imgUUID) {
        return imgUUID + IMG_SUFFIX;
    }

    /**
     * 生成新的文件名
     *
     * @return
     */
    public static String getNewFileName(String imgUUID, String extend) {
        return imgUUID + "." + extend;
    }


    /**
     * 上传图片
     *
     * @param file 文件
     * @param path 文件存放路径
     * @return
     */
    public static boolean uploadImage(MultipartFile file, String path, String imageId) throws GeneralSimpleException {
        // 生成新的文件名
        String rawPath = path + "/raw/" + getNewFileName(imageId);
        String prePath = path + "/pre/" + getNewFileName(imageId);
        File dest = new File(rawPath);
        //小于10M，才处理
        if(!dest.getParentFile().exists()){
            dest.getParentFile().mkdirs();
        }
        try {

            boolean b = testIfImageType(file);
            if (b) {
                
                byte[] imgZip = ImagePreviewUtils.smartZip(file, 100, 0.9f);
                if (imgZip != null) {
                    File preFile = new File(prePath);
                    FileUtils.writeByteArrayToFile(preFile, imgZip);
                }
            } else {
                LOG.error("Image Upload 文件 {} 不是受支持的压缩类型 imgId {}", file.getOriginalFilename(), imageId);
                throw new GeneralSimpleException("400012");
            }
            //保存源图片文件
            file.transferTo(dest);
            return true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
            LOG.error("上传文件错误1", e);
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            LOG.error("上传文件错误2", e);
            return false;
        }
    }

    /**
     * 上传图片
     *
     * @param file 文件
     * @param path 文件存放路径
     * @return
     */
    public static boolean uploadImage(File file, String path, String imageId) throws GeneralSimpleException {
        // 生成新的文件名
        String rawPath = path + "/raw/" + getNewFileName(imageId);
        File dest = new File(rawPath);
        //小于10M，才处理
        if(!dest.getParentFile().exists()){
            dest.getParentFile().mkdirs();
        }
        try {

            FileUtils.copyFile(file, dest);
            return true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
            LOG.error("上传文件错误1", e);
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            LOG.error("上传文件错误2", e);
            return false;
        }
    }
      
    public static String getAttachment(String path, String fileName) {
        return path + "/raw/" + fileName;
    }

    public static boolean checkFileType(InputStream inputStream, String type) throws GeneralSimpleException {
        String fileType = getFileType(inputStream, type);
        LOG.info("上传的附件类型:"+fileType);
        if (Objects.isNull(fileType)) {
            throw new GeneralSimpleException("400012");
        }
        if (StringUtils.equalsIgnoreCase(type, fileType)) {
            return true;
        } else if (StringUtils.equalsIgnoreCase(fileType, STRING_OFFICE)) {
            for (String supportOfficeSuffix : SUPPORT_OFFICE_SUFFIX) {
                if (StringUtils.equalsIgnoreCase(type, supportOfficeSuffix)) {
                    return true;
                }
            }
        } else if (StringUtils.equalsIgnoreCase(fileType, STRING_OFFICE_2)) {
            for (String supportOffice2Suffix : SUPPORT_OFFICE2_SUFFIX) {
                if (StringUtils.equalsIgnoreCase(type, supportOffice2Suffix)) {
                    return true;
                }
            }
        } else if (StringUtils.equalsIgnoreCase(fileType, STRING_JPG)) {
            for (String supportJpegSuffix : SUPPORT_JPEG_SUFFIX) {
                if (StringUtils.equalsIgnoreCase(type, supportJpegSuffix)) {
                    return true;
                }
            }
        }
        throw new GeneralSimpleException("400012");
    }

    /**
     * 上传附件
     *
     * @param file 文件
     * @param path 文件存放路径
     * @return
     */
    public static boolean uploadAttachment(MultipartFile file, String path, String fileName) throws GeneralSimpleException {
        // 生成新的文件名
        String rawPath = getAttachment(path, fileName);
        //path + "/raw/" + fileName;
        File dest = new File(rawPath);
        try {
            if(!dest.getParentFile().exists()){
                dest.getParentFile().mkdirs();
            }
            //保存附件
            file.transferTo(dest);

            return true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
            LOG.error("上传文件错误1", e);
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            LOG.error("上传文件错误2", e);
            return false;
        }
    }

    /**
     * 上传APP
     *
     * @param file 文件
     * @param filePath 文件存放路径
     * @return
     */
    public static boolean uploadAPP(MultipartFile file, String filePath) throws GeneralSimpleException {
        File dest = new File(filePath);
        try {
            if(!dest.getParentFile().exists()){
                dest.getParentFile().mkdirs();
            }
            //保存附件
            file.transferTo(dest);

            return true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
            LOG.error("上传文件错误1", e);
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            LOG.error("上传文件错误2", e);
            return false;
        }
    }


    public static boolean testIfImageType(MultipartFile file) {
        String contentType = null;
        try {
            contentType = FileTools.getFileType(file.getInputStream(),null);
            return isContainsContentType(contentType);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    private static Boolean isContainsContentType(String contentType) {
        if (StringUtils.isEmpty(contentType)) {
            return false;
        }
        for (String type : SUPPORT_FILE_SUFFIX) {
            if (contentType.equalsIgnoreCase(type)) {
                return true;
            }
        }
        return false;
    }

    public static String uploadXls(MultipartFile file) {
        String orgName = file.getOriginalFilename();
        String oldExt = StringUtils.substring(orgName,Objects.requireNonNull(orgName).lastIndexOf("."));
        String xlsDir = new File(System.getProperty("user.dir")) + "/xls/";
        String filePath = xlsDir + BaseCommonUtils.generateUUID() + oldExt;
        LOG.info("准备生成文件  {}", filePath);
        try {
            File xlsFile = new File(filePath);
            if (!xlsFile.getParentFile().exists()) {
                xlsFile.getParentFile().mkdirs();
            }
            file.transferTo(new File(filePath));
            return filePath;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}
